#include "server.h"

struct cnfg_info cnfg_info;
struct stat_info stat_info;
struct operate_info operate_info;

extern int worker_start(SOCKET **p_sock_pair);
extern int listener_start(SOCKET *sock_pair);
extern int monitor_start();

static int _cnfg(char *argv0)
{/*{{{*/
    char dirname[LONG_FILE_NM_SIZE+1];
    char buf[LONG_FILE_NM_SIZE+1];
    CNFG cnfg;
    struct cnfg_property property;
    int res;

    extract_dirname(argv0, dirname);

    /*----- cnfg -----*/
    sprintf(buf, "%s/server.cnfg", dirname);
    if((res=cnfg_load(buf, &cnfg)))
    {
        if(res > 0)
            fprintf(stderr, "%s: line %d error\n", __func__, res);
        else
            fprintf(stderr, "%s: load server.cnfg fail, res:%d\n",
                    __func__, res);
        return(-1);
    }

    // errlog
#ifdef _MY_DEBUG
    CLR_BUF(cnfg_info._errlog_.location);
#else
    strcpy(cnfg_info._errlog_.location, "./_log");
    res=cnfg_get_property(cnfg, "ERRLOG", "LOCATION", 0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            fprintf(stderr, "%s: get ERRLOG.LOCATION fail, res:%d\n",
                    __func__, res);
            return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
            strcpy(cnfg_info._errlog_.location, property.value);
    }
#endif
    res=cnfg_get_property(cnfg, "ERRLOG", "TRACKING", 0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            fprintf(stderr, "%s: get ERRLOG.TRACKING fail, res:%d\n",
                    __func__, res);
            return(-1);
        }
        cnfg_info._errlog_.tracking=IS_FALSE;
    }
    else
        cnfg_info._errlog_.tracking=IS_TRUE;

    // USER
    CLR_BUF(cnfg_info.user);
    res=cnfg_get_property(cnfg, NULL, "USER", 0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            fprintf(stderr, "%s: get USER fail, res:%d\n",
                    __func__, res);
            return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
        {
            if(strlen(property.value) > NAME_SIZE)
            {
                fprintf(stderr, "%s: USER invalid\n", __func__);
                return(-1);
            }
            strcpy(cnfg_info.user, property.value);
        }
    }

    // WORKERS
    cnfg_info.workers=1;
    res=cnfg_get_property(cnfg, NULL, "WORKERS", 0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            fprintf(stderr, "%s: get WORKERS fail, res:%d\n",
                    __func__, res);
            return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
        {
            int num=atoi(property.value);
            if(num < 1 || 8 < num)
            {
                fprintf(stderr, "%s: WORKERS invalid\n", __func__);
                return(-1);
            }
            cnfg_info.workers=num;
        }
    }

    // SERVER_PORT
    res=cnfg_get_property(cnfg, "ACCESS", "SERVER_PORT", 0, &property);
    if(res)
    {
        fprintf(stderr, "%s: get ACCESS.SERVER_PORT fail, errcode:%d\n",
                __func__, res);
        return(-1);
    }
    if(BUF_IS_CLR(property.value) || (res=atoi(property.value)) < 1024)
    {
        fprintf(stderr, "%s: ACCESS.SERVER_PORT invalid\n", __func__);
        return(-1);
    }
    cnfg_info._access_.server_port=res;

    // MONITOR_PORT
    res=cnfg_get_property(cnfg, "ACCESS", "MONITOR_PORT", 0, &property);
    if(res)
    {
        fprintf(stderr, "%s: get ACCESS.MONITOR_PORT fail, errcode:%d\n",
                __func__, res);
        return(-1);
    }
    if(BUF_IS_CLR(property.value) || (res=atoi(property.value)) < 1024)
    {
        fprintf(stderr, "%s: ACCESS.MONITOR_PORT invalid\n", __func__);
        return(-1);
    }
    cnfg_info._access_.monitor_port=res;

    // DB 
    res=cnfg_get_property(cnfg, "DB", "USER", 0, &property);
    if(res || BUF_IS_CLR(property.value)
            || strlen(property.value) > NAME_SIZE)
    {
        fprintf(stderr, "%s: DB.USER invalid\n", __func__);
        return(-1);
    }
    strcpy(cnfg_info._db_.user, property.value);

    res=cnfg_get_property(cnfg, "DB", "PASSWD", 0, &property);
    if(res || BUF_IS_CLR(property.value)
            || strlen(property.value) > PASSWD_ENC_SIZE)
    {
        fprintf(stderr, "%s: DB.PASSWD invalid\n", __func__);
        return(-1);
    }
    strcpy(cnfg_info._db_.passwd, property.value);

    res=cnfg_get_property(cnfg, "DB", "DATABASE", 0, &property);
    if(res || BUF_IS_CLR(property.value)
            || strlen(property.value) > NAME_SIZE)
    {
        fprintf(stderr, "%s: DB.DATABASE invalid\n", __func__);
        return(-1);
    }
    strcpy(cnfg_info._db_.database, property.value);

    CLR_BUF(cnfg_info._db_.host);
    res=cnfg_get_property(cnfg, "DB", "HOST", 0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            fprintf(stderr, "%s: get DB.HOST fail, res:%d\n",
                    __func__, res);
            return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
        {
            if(strlen(property.value) > NAME_SIZE)
            {
                fprintf(stderr, "%s: DB.HOST invalid\n", __func__);
                return(-1);
            }
            strcpy(cnfg_info._db_.host, property.value);
        }
    }

    cnfg_free(cnfg);

    return(0);
}/*}}}*/

static int _start(char *argv0)
{/*{{{*/
    SOCKET *sock_pair;
    int worker_idx;
    int res;

    sig_ignore(SIGPIPE);
    ep_init();
    //mysqlc_init();
    //oraproc_init();

#ifdef _MY_DEBUG
    init_errlog(argv0, NULL);
#else
    res=init_errlog(argv0, cnfg_info._errlog_.location);
    if(res)
    {
        fprintf(stderr, "%s: init_errlog fail, res:%d\n",
                __func__, res);
        return(-1);
    }
#endif

    if(getuid() == 0)
    {
        struct passwd *user=getpwnam(cnfg_info.user);
        if(user)
        {
            if(setuid(user->pw_uid) == -1)
            {
                fprintf(stderr, "Change to user %s fail\n",
                        cnfg_info.user);
                return(-1);
            }
            fprintf(stderr, "Change to user %s\n", cnfg_info.user);
        }
        else
        {
            fprintf(stderr, "User %s not found, keep root\n",
                    cnfg_info.user);
        }
    }

    ALLOC_MULTI_DOERR(cnfg_info._db_.db, MYSQLC, cnfg_info.workers, 
            fprintf(stderr, "%s: alloc cnfg_info._db_.db fail\n",
                __func__);
            return(-1));
    for(worker_idx=0; worker_idx<cnfg_info.workers; ++worker_idx)
    {
        //        res=mysqlc_connect_ex(cnfg_info._db_.user,
        //                        cnfg_info._db_.passwd,
        //                        cnfg_info._db_.database,
        //                        cnfg_info._db_.host,
        //                        &cnfg_info._db_.db[worker_idx]);
        //        if(res != MY_OK)
        //        {
        //            fprintf(stderr,
        //            "%s: worker(%d) connect to db fail, res:%d\n",
        //                    __func__, worker_idx, res);
        //            return(-1);
        //        }
        //
        //        res=oraproc_connect_ex(cnfg_info._db_.user,
        //                        cnfg_info._db_.passwd,
        //                        cnfg_info._db_.host,
        //                        &cnfg_info._db_.db[worker_idx]);
        //        if(res != ORA_OK)
        //        {
        //            fprintf(stderr,
        //            "%s: worker(%d) connect to db fail, res:%d\n",
        //                    __func__, worker_idx, res);
        //            return(-1);
        //        }
    }

    if(worker_start(&sock_pair))
    {
        fprintf(stderr, "%s: worker_start fail\n", __func__);
        return(-1);
    }
    if(listener_start(sock_pair))
    {
        fprintf(stderr, "%s: listener_stat fail\n", __func__);
        return(-1);
    }
    free(sock_pair);

    return(monitor_start());
}/*}}}*/

int main(int argc, char *argv[])
{
#ifndef _MY_DEBUG
    daemon(1, 1);
#endif
    if(_cnfg(argv[0]))
        return(-1);
    return(_start(argv[0]));
}
